package com.sc.nft.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.DaoWalletDetailDao;
import com.sc.nft.dao.MallDaoWalletDao;
import com.sc.nft.dao.MallDaoWalletDetailDao;
import com.sc.nft.entity.MallDaoWallet;
import com.sc.nft.entity.MallDaoWalletDetail;
import com.sc.nft.enums.wallet.MallDaoWalletTypeEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.MallDaoWalletService;
import com.sc.nft.util.BigDecimalUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;

/**
 * <p>
 * 商城dao钱包 服务实现类
 * </p>
 *
 * @author ligen
 * @since 2024-01-17
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MallDaoWalletServiceImpl implements MallDaoWalletService {

    private final MallDaoWalletDao mallDaoWalletDao;
    private final MallDaoWalletDetailDao mallDaoWalletDetailDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addBalance(Long daoId, BigDecimal amount, BigDecimal activityAmount, BigDecimal charge, MallDaoWalletTypeEnum type, String remark) {
        MallDaoWallet wallet = mallDaoWalletDao.getByDaoId(daoId);
        MallDaoWalletDetail detail = new MallDaoWalletDetail();
        detail.setDaoId(wallet.getDaoId());
        detail.setAmount(amount);
        detail.setCharge(charge);
        detail.setRealAmount(amount.subtract(charge));
        detail.setBeforeAmount(wallet.getBalance());
        detail.setIsAdd(true);
        detail.setAfterAmount(wallet.getBalance().add(detail.getRealAmount()));
        detail.setType(type);
        detail.setRemark(remark);
        detail.insert();
        if (Objects.nonNull(activityAmount) && BigDecimalUtils.greaterZero(activityAmount)) {
            MallDaoWalletDetail activityAmountdetail = new MallDaoWalletDetail();
            activityAmountdetail.setDaoId(wallet.getDaoId());
            activityAmountdetail.setAmount(activityAmount);
            activityAmountdetail.setCharge(BigDecimal.ZERO);
            activityAmountdetail.setRealAmount(activityAmount);
            activityAmountdetail.setBeforeAmount(wallet.getActivityBalance());
            activityAmountdetail.setIsAdd(true);
            activityAmountdetail.setAfterAmount(wallet.getActivityBalance().add(activityAmount));
            activityAmountdetail.setType(MallDaoWalletTypeEnum.MALL_ORDER_ACTIVITY_SETTLEMENT);
            activityAmountdetail.setRemark(MallDaoWalletTypeEnum.MALL_ORDER_ACTIVITY_SETTLEMENT.getDescription());
            activityAmountdetail.insert();
            mallDaoWalletDao.addActivityBalance(daoId, activityAmountdetail.getRealAmount());
        }

        mallDaoWalletDao.addBalance(daoId, detail.getRealAmount());
    }

    /**
     * 转出冻结余额
     *
     * @param daoId
     * @param amount
     * @param charge
     * @param type
     * @param remark
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void freezeBalance(Long daoId, BigDecimal amount, BigDecimal charge, MallDaoWalletTypeEnum type, String remark) {
        MallDaoWallet wallet = mallDaoWalletDao.getByDaoId(daoId);
        Assert.isTrue(NumberUtil.isGreaterOrEqual(wallet.getBalance(), amount), () -> new GlobalRunTimeException("可用余额不足"));
        MallDaoWalletDetail detail = new MallDaoWalletDetail();
        detail.setDaoId(wallet.getDaoId());
        detail.setAmount(amount);
        detail.setCharge(charge);
        detail.setRealAmount(amount.subtract(charge));
        detail.setBeforeAmount(wallet.getBalance());
        detail.setIsAdd(false);
        detail.setAfterAmount(wallet.getBalance().subtract(detail.getRealAmount()));
        detail.setType(type);
        detail.setRemark(remark);
        detail.insert();
        mallDaoWalletDao.approval(daoId, detail.getRealAmount());
    }

    @Override
    public MallDaoWallet getByDaoId(Long daoId) {
        return mallDaoWalletDao.getByDaoId(daoId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refuse(Long daoId, BigDecimal amount) {
        MallDaoWallet wallet = mallDaoWalletDao.getByDaoId(daoId);
        MallDaoWalletDetail detail = new MallDaoWalletDetail();
        detail.setDaoId(wallet.getDaoId());
        detail.setAmount(amount);
        detail.setCharge(BigDecimal.ZERO);
        detail.setRealAmount(amount);
        detail.setBeforeAmount(wallet.getBalance());
        detail.setIsAdd(true);
        detail.setAfterAmount(wallet.getBalance().add(detail.getRealAmount()));
        detail.setType(MallDaoWalletTypeEnum.TRANSFER_REFUND);
        detail.setRemark(detail.getType().getDescription());
        detail.insert();
        mallDaoWalletDao.refuse(daoId, detail.getRealAmount());
    }

    @Override
    public Page<MallDaoWalletDetail> getDaoWalletDetailPage(Long daoId, MallDaoWalletTypeEnum type, Date startTime, Date endTime, Page page, Boolean isActivity) {
        return mallDaoWalletDetailDao.getDaoWalletDetailPage(daoId, type, startTime, endTime, page, isActivity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void subBalance(Long daoId, BigDecimal amount, BigDecimal charge, MallDaoWalletTypeEnum type, String remark) {
        MallDaoWallet wallet = mallDaoWalletDao.getByDaoId(daoId);
        MallDaoWalletDetail detail = new MallDaoWalletDetail();
        detail.setDaoId(wallet.getDaoId());
        detail.setAmount(amount);
        detail.setCharge(charge);
        detail.setRealAmount(amount);
        detail.setBeforeAmount(wallet.getBalance());
        detail.setIsAdd(Boolean.FALSE);
        detail.setAfterAmount(wallet.getBalance().subtract(detail.getRealAmount()));
        detail.setType(type);
        detail.setRemark(remark);
        detail.insert();
        mallDaoWalletDao.subBalance(daoId, detail.getRealAmount());
    }
}
